<?php

/*
 * 文件缓存类
 */
 
class Cache_file {

	//缓存文件存放目录
	protected $path = './cache/';
	
	//缓存目录层级，支持1,2,3级
	protected $level = 1;
	
	//缓存时间
	protected $expiration = 3600;
	
	protected $_valid = array(
		'path',
		'level',
		'expiration'
	);
	public function __construct($config = array())
	{
		if ($config)
		{
			$this->config($config);
		}
	}
	
	/*
	 * 初始化
	 * @access	public
	 * @return	boolean
	 */
	public function init()
	{
		if ( ! $this->validate_path())
		{
			$this->set_error('缓存目录'.$this->path.'不存在或不可写！');
			return FALSE;
		}
		return TRUE;
	}
	
	/*
	 * 验证缓存目录
	 * @access	protected
	 * @return	boolean
	 */
	protected function validate_path()
	{
		if (FALSE == ($path = realpath($this->path)))
		{
			return FALSE;
		}
		
		$this->path = rtrim(str_replace('\\', '/', $path), '/').'/';
		
		if ( ! is_dir($this->path))
		{
			return FALSE;
		}

		if ( ! is_really_writable($this->path))
		{
			return FALSE;
		}
		
		return TRUE;
	}

	/*
	 * 根据id返回这个id的缓存文件地址
	 * @access	public
	 * @param	$id string 缓存名称
	 * @return	string or boolean
	 */
	public function get_filename($id)
	{		
		$id = md5($id);
		$arr = str_split($id);
		$filename = '';
		switch ($this->level)
		{
			case 1:
				$filename = $this->path.(hexdec($arr[0])*hexdec($arr[1])).'/'.$id;
				break;
			case 2:
				$filename = $this->path.(hexdec($arr[0])*hexdec($arr[1])).'/'.(hexdec($arr[2])*hexdec($arr[3])).'/'.$id;
				break;
			case 3:
				$filename = $this->path.(hexdec($arr[0])*hexdec($arr[1])).'/'.(hexdec($arr[2])*hexdec($arr[3])).'/'.(hexdec($arr[4])*hexdec($arr[5])).'/'.$id;
				break;
			default:
				$filename = $this->path.(hexdec($arr[0])*hexdec($arr[1])).'/'.$id;
				break;
		}

		return $filename;
	}
	
	/*
	 * 获取缓存完整信息
	 * @access	protected
	 * @param	$id string 缓存名称
	 * @return	mixed
	 */
	protected function _get($id)
	{	
		$filename = $this->get_filename($id);
		
		if ( ! $filename)
		{
			return FALSE;
		}

		if (FALSE == ($content = read_file($filename)))
		{
			$this->set_error('读取缓存文件'.$filename.'失败！');
			return FALSE;
		}
		
		$result = unserialize($content);
		
		if ( ! is_array($result) && count($result) != 3)
		{
			return FALSE;
		}
		
		list($data, $time, $expiration) = $result;
		
		if ($expiration == 0 || time() < ($time + $expiration))
		{
			return array(
				'data' => $data,
				'time' => $time,
				'expiration' => $expiration
			);
		}
		
		@unlink($filename);
		return FALSE;
	}

	/*
	 * 获取缓存
	 * @access	public
	 * @param	$id string 缓存名称
	 * @return	mixed
	 */
	public function get($id)
	{	
		$result = $this->_get($id);
		return $result ? $result['data'] : FALSE; 
	}
	
	/*
	 * 返回缓存详细信息
	 * @access	public
	 * @param	$id string 键名
	 * @return	array or boolean
	 */
	public function detail($id)
	{
		$result = $this->_get($id);
		return $result;
	}

	/*
	 * 写入缓存
	 * @access	public
	 * @param	$id string 缓存键名
	 * @param	$data mixed 缓存结果
	 * $param	$expiration integer 缓存时间
	 * @return	boolean
	 */
	public function set($id, $data, $expiration = NULL)
	{	
		$expiration = ($expiration !== NULL) ? intval($expiration) : intval($this->expiration);
		$expiration = $expiration > 0 ? $expiration : 0;
		
		$filename = $this->get_filename($id);

		if ( ! $filename)
		{
			return FALSE;
		}

		$path = dirname($filename);
		
		if ( ! is_dir($path))
		{
			if ( ! create_dir($path))
			{
				$this->set_error('创建目录'.$path.'失败！');
			}
		}
		
		$content = serialize(array($data, time(), $expiration));
		
		if ( ! write_file($filename, $content))
		{
			$this->set_error('写入缓存文件'.$filename.'失败！');
			return FALSE;
		}
		
		return TRUE;
	}

	/*
	 * 删除缓存
	 * @access	public
	 * @param	$id string 缓存名称
	 * @return	boolean
	 */
	public function delete($id)
	{	
		$filename = $this->get_filename($id);
		
		if ( ! $filename)
		{
			return FALSE;
		}
		
		if ( ! @unlink($filename))
		{
			$this->set_error('删除缓存文件'.$filename.'失败！');
			return FALSE;
		}
		
		return TRUE;
	}

	/*
	 * 清空缓存
	 * @access	public
	 * @return	boolean
	 */
	public function clean()
	{
		if ( ! clean_dir($this->path))
		{
			$this->set_error('清空缓存目录'.$this->path.'失败');
			return FALSE;
		}
		return TRUE;
	}
	
	public function set_path($path)
	{
		$this->path = trim($path);
		return $this;
	}
	
	public function set_level($level)
	{
		$this->level = in_array(intval($level), array(1, 2, 3)) ? intval($level) : 1;
		return $this;
	}
	
	public function set_expiration($expiration)
	{
		$this->expiration = intval($expiration) > 0 ? intval($expiration) : 0;
		return $this;
	}

}